"use strict";(self.webpackChunk_N_E=self.webpackChunk_N_E||[]).push([[33945],{37990:(e,a,t)=>{t.d(a,{ReportButton:()=>i});var l=t(95155),s=t(12115);let n=[{key:"spam",label:"광고/스팸"},{key:"abuse",label:"욕설/비방"},{key:"spoiler",label:"스포일러 포함"},{key:"porn",label:"음란물"},{key:"illegal",label:"불법정보"},{key:"personal",label:"개인정보 노출"},{key:"other",label:"기타"}];function i({targetType:e,targetId:a,loggedIn:t,className:r,hidden:d}){let[o,c]=(0,s.useState)(!1),[u,h]=(0,s.useState)("spam"),[p,m]=(0,s.useState)(""),[b,k]=(0,s.useState)(!1),[f,x]=(0,s.useState)(!1);if(d)return null;let j=async()=>{if(!t)return void alert("로그인 후 이용해주세요");if(!b){k(!0);try{let t=await fetch("/api/board/report",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({targetType:e,targetId:a,reason:u,detail:p})}),l=await t.json().catch(()=>null);if(!t.ok||!l?.ok){alert(l?.error||`신고 실패 (${t.status})`),k(!1);return}x(!0),k(!1),setTimeout(()=>{c(!1)},1200)}catch(e){alert(e instanceof Error?e.message:"신고 실패"),k(!1)}}};return(0,l.jsxs)(l.Fragment,{children:[(0,l.jsxs)("button",{type:"button",className:`report-btn${r?` ${r}`:""}`,onClick:()=>{t?(c(!0),x(!1)):alert("로그인 후 이용해주세요")},title:"신고","aria-label":"신고",children:[(0,l.jsx)("span",{className:"report-btn-icon","aria-hidden":!0,children:"\uD83D\uDEA9"}),(0,l.jsx)("span",{className:"report-btn-text",children:"신고"})]}),o&&(0,l.jsxs)("div",{className:"report-modal",role:"dialog","aria-modal":"true","aria-label":"신고",children:[(0,l.jsx)("div",{className:"report-modal-backdrop",onClick:()=>!b&&c(!1)}),(0,l.jsxs)("div",{className:"report-modal-card",children:[(0,l.jsxs)("div",{className:"report-modal-head",children:[(0,l.jsxs)("span",{children:["\uD83D\uDEA9 ","post"===e?"글":"댓글"," 신고"]}),(0,l.jsx)("button",{type:"button",className:"report-modal-close",onClick:()=>!b&&c(!1),"aria-label":"닫기",children:"✕"})]}),f?(0,l.jsxs)("div",{className:"report-modal-done",children:[(0,l.jsx)("div",{className:"report-modal-done-em",children:"✅"}),(0,l.jsx)("div",{children:"신고가 접수되었습니다."}),(0,l.jsx)("div",{className:"report-modal-done-sub",children:"관리자가 검토 후 처리합니다."})]}):(0,l.jsxs)("div",{className:"report-modal-body",children:[(0,l.jsx)("p",{className:"report-modal-desc",children:"허위 신고는 본인이 신고당해 패널티를 받을 수 있습니다. (1회 -300P, 2회 -500P, 3회 -1000P, 4회 영구차단)"}),(0,l.jsxs)("label",{className:"report-modal-field",children:[(0,l.jsx)("span",{className:"report-modal-label",children:"사유"}),(0,l.jsx)("div",{className:"report-modal-reasons",children:n.map(e=>(0,l.jsx)("button",{type:"button",className:`report-modal-reason${u===e.key?" is-active":""}`,onClick:()=>h(e.key),children:e.label},e.key))})]}),(0,l.jsxs)("label",{className:"report-modal-field",children:[(0,l.jsxs)("span",{className:"report-modal-label",children:["상세 내용 ",(0,l.jsx)("span",{className:"report-modal-hint",children:"(선택, 최대 400자)"})]}),(0,l.jsx)("textarea",{className:"report-modal-textarea",rows:4,maxLength:400,value:p,onChange:e=>m(e.target.value),placeholder:"구체적인 사유를 남기면 빠르게 처리됩니다."})]}),(0,l.jsxs)("div",{className:"report-modal-actions",children:[(0,l.jsx)("button",{type:"button",className:"btn btn--outline",onClick:()=>!b&&c(!1),disabled:b,children:"취소"}),(0,l.jsx)("button",{type:"button",className:"btn btn--danger",onClick:j,disabled:b,children:b?"전송 중...":"신고 접수"})]})]})]})]})]})}},52438:(e,a,t)=>{t.d(a,{s:()=>s});var l=t(95155);function s({points:e,level:a,role:t,extraRoles:n,isBoardAdmin:i,avatarUrl:r,className:d,size:o=22,anonymous:c}){var u;if(c)return(0,l.jsx)("span",{className:`lv-pill lv-pill--anon ${d??""}`,title:"익명게시자",style:{width:o,height:o},children:"❓"});let h="admin"===t||Array.isArray(n)&&n.includes("admin"),p=a??((u=e??0)&&!(u<1e3)?Math.min(1+Math.floor(Math.sqrt(u/1e3)),99):1),m=!!i&&!h,b=p>=70?"cosmic":p>=45?"aurora":p>=25?"shimmer":p>=5?"glow":"plain",k=function(e){let a=Math.max(1,Math.min(99,Math.floor(e)));if(1===a)return{bgLight:"hsl(220 6% 78%)",bgMid:"hsl(220 6% 64%)",bgDark:"hsl(220 6% 48%)",fg:"hsl(220 10% 22%)"};let t=((220-(a-2)*12)%360+360)%360,l=50+Math.round((a-2)/97*42),s=70-Math.round((a-2)/97*28),n=Math.min(92,s+18),i=Math.max(18,s-22),r=`hsl(${t} ${l}% ${n}%)`,d=`hsl(${t} ${l}% ${s}%)`;return{bgLight:r,bgMid:d,bgDark:`hsl(${t} ${l}% ${i}%)`,fg:s>=55?`hsl(${t} 60% 18%)`:`hsl(${t} 30% 96%)`}}(p),f={background:`linear-gradient(160deg, ${k.bgLight}, ${k.bgMid} 55%, ${k.bgDark})`,color:k.fg},x=1===p,j=x?"뉴비":String(p),g=x?"레벨 1 \xb7 뉴비":`레벨 ${p}`,N=x?{fontSize:Math.max(8,Math.round(.4*o)),letterSpacing:"-0.04em"}:null;if(r){let e=h?"lv-pill--admin":m?"lv-pill--board-admin":`lv-pill--fx-${b}`,a=h?"M":m?"★":j,t=h?"운영자":m?"게시판 관리자":g,s=o-4,n=!x||h||m?null:{fontSize:Math.max(7,Math.round(.4*s)),letterSpacing:"-0.05em"},i=h||m?{width:s,height:s}:{width:s,height:s,...f,...n};return(0,l.jsxs)("span",{className:`lv-with-avatar ${d??""}`,title:t,children:[(0,l.jsx)("img",{src:r,alt:"",className:"lv-avatar",style:{width:o,height:o},loading:"lazy"}),(0,l.jsx)("span",{className:`lv-pill ${e}`,style:i,children:a})]})}return m?(0,l.jsxs)("span",{className:`lv-with-avatar ${d??""}`,title:`${g} \xb7 게시판 관리자`,children:[(0,l.jsx)("span",{className:`lv-pill lv-pill--fx-${b}`,style:{width:o,height:o,...f,...N},children:j}),(0,l.jsx)("span",{className:"lv-pill lv-pill--board-admin",style:{width:o-4,height:o-4},children:"★"})]}):h?(0,l.jsx)("span",{className:`lv-pill lv-pill--admin ${d??""}`,title:"운영자",style:{width:o,height:o},children:"M"}):(0,l.jsx)("span",{className:`lv-pill lv-pill--fx-${b} ${d??""}`,title:g,style:{width:o,height:o,...f,...N},children:j})}},64027:(e,a,t)=>{t.d(a,{AdminBlockButtons:()=>i});var l=t(95155),s=t(12115);function n(e,a,t,l){let s=t.filter(e=>e.id!==l);if(0===s.length)return`${e} ${a} → 이 작성자만 사용 (충돌 없음)`;let n=s.map(e=>`${e.nickname}(id ${e.id})`).join(", ");return`${e} ${a} → 같이 차단되는 사용자 ${s.length}명: ${n}`}function i({authorId:e,authorNickname:a,authorIp:t,authorFp:r,ipCollision:d,fpCollision:o,reason:c,triggerPostId:u,onSuccess:h,className:p,userOnly:m=!1}){let[b,k]=(0,s.useTransition)(),f=l=>{let s=l.map(e=>e.toUpperCase()).join("+"),i=[];i.push(`작성자(${a}, id ${e})를 ${s} 로 차단합니다.`),i.push(""),i.push(`사유: ${c}`),i.push(""),l.includes("ip")&&t&&i.push(n("IP",t,d,e)),l.includes("fp")&&r&&i.push(n("FP",r,o,e)),i.push(""),i.push("차단되는 사용자들의 모든 글/댓글이 삭제됩니다."),u&&i.push("(이 글은 사유 추적을 위해 유지됨)"),l.includes("ip")&&i.push("Cloudflare 방화벽에도 영구 등록됩니다."),i.push(""),i.push("진행할까요?"),confirm(i.join("\n"))&&k(async()=>{let a=[],n=!1;for(let s=0;snull);if(!h.ok||!p?.ok)return void alert(`${i.toUpperCase()} 차단 실패: ${p?.error??h.status}`);if(n=!0,"ip"===i){let e=p?.cloudflare??[];e.length>0&&a.push(e.every(e=>e.ok)?"Cloudflare 등록 성공":`Cloudflare 일부 실패: ${e.find(e=>!e.ok)?.error??""}`)}0===s&&(p?.bannedUsers??0)>0&&a.push(`회원 ${p.bannedUsers}명 영구정지 (세션 ${p.sessionsKilled??0}개 종료)`)}alert(`${s} 차단 완료${a.length?"\n"+a.join("\n"):""}`),h?h():window.location.reload()})};return(0,l.jsxs)("span",{className:`admin-block-btns ${p??""}`,children:[(0,l.jsx)("button",{type:"button",className:"btn btn--outline post-del",onClick:()=>{let t=[`작성자(${a}, id ${e}) 계정만 영구 정지합니다.`,"",`사유: ${c}`,"","이 계정의 모든 글/댓글이 삭제됩니다 (게시판/작품/만화/소설 전부)."];u&&t.push("(이 글은 사유 추적을 위해 유지됨)"),t.push("","⚠ IP/FP 는 차단하지 않습니다 — 같은 IP/FP 의 다른 계정으로 재가입 가능.","","진행할까요?"),confirm(t.join("\n"))&&k(async()=>{let a={kind:"user",value:e,reason:c,purge:"1",banUser:"1",trigger_author_id:e};u&&(a.trigger_post_id=u);let t=await fetch("/api/admin/ban",{method:"POST",headers:{"Content-Type":"application/json",Accept:"application/json"},body:JSON.stringify(a)}),l=await t.json().catch(()=>null);t.ok&&l?.ok?(alert(`계정 차단 완료 회원 ${l.bannedUsers??0}명 영구정지 (세션 ${l.sessionsKilled??0}개 종료) 글 ${l.purgedPosts??0}개 \xb7 댓글 ${l.purgedComments??0}개 삭제`),h?h():window.location.reload()):alert(`계정 차단 실패: ${l?.error??t.status}`)})},disabled:b,title:"계정만 영구정지 (IP/FP 미차단). 같은 IP/FP 의 다른 사용자는 영향 없음.",children:"\uD83D\uDEAB 계정만+삭제"}),!m&&t&&(0,l.jsx)("button",{type:"button",className:"btn btn--outline post-del",onClick:()=>f(["ip"]),disabled:b,title:`계정 + IP 차단 (IP: ${t}). 같은 IP 사용자 다 ban. Cloudflare 도 등록.`,children:"\uD83D\uDEAB 계정+IP차단+삭제"}),!m&&r&&(0,l.jsx)("button",{type:"button",className:"btn btn--outline post-del",onClick:()=>f(["fp"]),disabled:b,title:`계정 + FP 차단 (FP: ${r}). FP collision 있으면 skip.`,children:"\uD83D\uDEAB 계정+FP차단+삭제"}),!m&&t&&r&&(0,l.jsx)("button",{type:"button",className:"btn btn--outline post-del",onClick:()=>f(["ip","fp"]),disabled:b,title:"계정 + IP + FP 동시 차단. 가장 강한 옵션.",children:"\uD83D\uDEAB 계정+IP+FP차단+삭제"})]})}},71595:(e,a,t)=>{t.d(a,{NicknameDropdown:()=>o});var l=t(95155),s=t(12115),n=t(47650),i=t(73321);let r={admin:"관리자",manhwa_editor:"만화 관리자",uploader:"업로더",user:"회원",banned:"정지된 회원"},d={admin:"nick-dd-role-admin",manhwa_editor:"nick-dd-role-editor",uploader:"nick-dd-role-uploader",banned:"nick-dd-role-banned"};function o({userId:e,nickname:a,isBlockedByMe:t=!1,searchHref:c,isMe:u=!1,targetIsAdmin:h=!1,role:p,points:m,avatarUrl:b,className:k,effect:f,children:x}){let j=f?[f.rainbow?"nick-fx-rainbow":"",f.glow?"nick-fx-glow":"",f.bold?"nick-fx-bold":"",f.color?"nick-fx-color":"",f.frame?"nick-fx-frame":""].filter(Boolean).join(" "):"",g=f?.color?{color:f.color}:void 0,N=(0,i.useRouter)(),[$,v]=(0,s.useState)(!1),[y,w]=(0,s.useState)(t),[P,C]=(0,s.useTransition)(),[S,M]=(0,s.useState)(null),E=(0,s.useRef)(null),I=(0,s.useRef)(null);if((0,s.useEffect)(()=>{w(t)},[t]),(0,s.useLayoutEffect)(()=>{if(!$)return;let e=E.current?.getBoundingClientRect();if(e){let a=e.left;a+260>window.innerWidth-8&&(a=Math.max(8,e.right-260));let t=e.bottom+6;t+240>window.innerHeight-8&&(t=Math.max(8,e.top-240-6)),M({top:t,left:a})}},[$]),(0,s.useEffect)(()=>{if(!$)return;let e=e=>{let a=e.target;E.current?.contains(a)||I.current?.contains(a)||v(!1)},a=e=>{"Escape"===e.key&&v(!1)},t=()=>v(!1);return document.addEventListener("click",e),document.addEventListener("keydown",a),window.addEventListener("scroll",t,{passive:!0}),()=>{document.removeEventListener("click",e),document.removeEventListener("keydown",a),window.removeEventListener("scroll",t)}},[$]),u)return(0,l.jsx)("span",{className:`nick-dd nick-dd--me ${j} ${k??""}`,style:g,children:x});let _=p??"user",F=r[_]??"회원",L=d[_]??"";return(0,l.jsxs)("span",{className:`nick-dd ${j} ${k??""}`,style:g,children:[(0,l.jsx)("button",{ref:E,type:"button",className:"nick-dd-trigger",onClick:e=>{e.preventDefault(),e.stopPropagation(),v(e=>!e)},children:x}),$&&S&&"u">typeof document&&(0,n.createPortal)((0,l.jsxs)("div",{ref:I,className:"nick-dd-menu",role:"menu",style:{position:"fixed",top:S.top,left:S.left},children:[(0,l.jsxs)("div",{className:"nick-dd-card",children:[(0,l.jsx)("div",{className:"nick-dd-card-avatar",children:b?(0,l.jsx)("img",{src:b,alt:""}):(0,l.jsx)("span",{className:"nick-dd-card-avatar-fallback",children:a.slice(0,1)})}),(0,l.jsxs)("div",{className:"nick-dd-card-meta",children:[(0,l.jsx)("div",{className:"nick-dd-card-name",children:a}),(0,l.jsxs)("div",{className:"nick-dd-card-row",children:[(0,l.jsx)("span",{className:`nick-dd-card-role ${L}`,children:F}),"number"==typeof m&&m>0&&(0,l.jsxs)("span",{className:"nick-dd-card-pts",children:[m.toLocaleString(),"P"]})]})]})]}),(0,l.jsx)("div",{className:"nick-dd-divider"}),(0,l.jsxs)("div",{className:"nick-dd-list",children:[c&&(0,l.jsxs)("button",{type:"button",className:"nick-dd-item",onClick:()=>{c&&(v(!1),N.push(`${c}?nick=${encodeURIComponent(a)}`))},disabled:P,children:[(0,l.jsx)("span",{className:"nick-dd-ico",children:"\uD83D\uDD0D"}),(0,l.jsxs)("span",{className:"nick-dd-item-body",children:[(0,l.jsx)("span",{className:"nick-dd-item-label",children:"이 닉네임으로 검색"}),(0,l.jsx)("span",{className:"nick-dd-item-sub",children:"이 게시판에서 작성 글 모아보기"})]})]}),!h&&(0,l.jsxs)("button",{type:"button",className:`nick-dd-item ${y?"nick-dd-item--unblock":"nick-dd-item--block"}`,onClick:()=>{P||C(async()=>{try{if(y){let a=await fetch(`/api/me/blocks?userId=${encodeURIComponent(e)}`,{method:"DELETE"}),t=await a.json().catch(()=>null);if(!a.ok||!t?.ok)return void alert(t?.error||`해제 실패 (${a.status})`);w(!1)}else{if(!confirm(`${a} 님을 차단할까요? 이 사용자의 글/댓글이 본인 화면에서 가려집니다.`))return;let t=(window.prompt("차단 사유 (선택 \xb7 본인만 볼 수 있어요)","")||"").trim().slice(0,200),l=await fetch("/api/me/blocks",{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({targetUserId:e,reason:t})}),s=await l.json().catch(()=>null);if(!l.ok||!s?.ok)return void alert(s?.error||`차단 실패 (${l.status})`);w(!0)}v(!1),N.refresh()}catch(e){alert(e instanceof Error?e.message:"오류")}})},disabled:P,children:[(0,l.jsx)("span",{className:"nick-dd-ico",children:y?"✓":"\uD83D\uDEAB"}),(0,l.jsxs)("span",{className:"nick-dd-item-body",children:[(0,l.jsx)("span",{className:"nick-dd-item-label",children:y?"차단 해제":"차단"}),(0,l.jsx)("span",{className:"nick-dd-item-sub",children:y?"다시 보이게 합니다":"글/댓글이 내 화면에서 가려집니다"})]}),P&&(0,l.jsx)("span",{className:"nick-dd-spinner",children:"⌛"})]}),h&&(0,l.jsx)("div",{className:"nick-dd-disabled",children:"관리자는 차단할 수 없습니다"})]})]}),document.body)]})}},73321:(e,a,t)=>{var l=t(74645);t.o(l,"usePathname")&&t.d(a,{usePathname:function(){return l.usePathname}}),t.o(l,"useRouter")&&t.d(a,{useRouter:function(){return l.useRouter}}),t.o(l,"useSearchParams")&&t.d(a,{useSearchParams:function(){return l.useSearchParams}})}}]);